package com.common.utils;

import com.common.entity.user.GrantedAuthority;
import com.common.entity.user.SecurityUser;
import com.common.global.BizException;
import com.common.global.CommonEnum;
import com.common.properties.JwtProperties;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;


import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * JwtTokenUtils
 *
 * @author johnny
 * @create 2020-07-18 下午7:00
 **/
@Slf4j
@Component
public class JwtTokenUtils implements ApplicationContextAware {

    private static JwtProperties jwtProperties;


    public static final String getJwtToken(SecurityUser securityUser) {
        //当前时间
        long now = System.currentTimeMillis();

        long exp = now + 1000 * 60 * 60 * jwtProperties.getExpirationHour();
        //long exp = now + 1000 * 20 * jwtProperties.getExpirationHour();
        //过期时间为1分钟
        //long exp = now + 1000 * 60 * jwtProperties.getExpirationHour();
        //long exp = now + 10 * 60;
        String token = Jwts.builder()
                //主题 放入用户名
                .setSubject(jwtProperties.getJwtSubject())
                //自定义属性 放入用户拥有请求权限
                .claim("username", securityUser.getUsername())
                .claim("userId", securityUser.getUserId())
                .claim("roles", securityUser.getRoles())
                //失效时间
                .setExpiration(new Date(exp))
                //签名算法和密钥
                .signWith(SignatureAlgorithm.HS512, jwtProperties.getJwtSigningKey())
                .compact();
        log.debug("【jwt token str: {}】", token);
        return token;
    }

    public static final String getRefreshJwtToken(SecurityUser securityUser) {

        //当前时间
        long now = System.currentTimeMillis();

        //long exp = now + 1000 * 60  * jwtProperties.getExpirationHour() * 2;
        //过期时间为1分钟
        long exp = now + 1000 * 60 * 60 * jwtProperties.getExpirationHour() * 2;
        //long exp = now + 10 * 60;
        String token = Jwts.builder()
                //主题 放入用户名
                .setSubject(jwtProperties.getJwtSubject())
                //自定义属性 放入用户拥有请求权限
                .claim("username", securityUser.getUsername())
                .claim("userId", securityUser.getUserId())
                .claim("roles", securityUser.getRoles())
                //失效时间
                .setExpiration(new Date(exp))
                //签名算法和密钥
                .signWith(SignatureAlgorithm.HS512, jwtProperties.getJwtSigningKey())
                .compact();
        log.debug("【jwt token str: {}】", token);
        return token;
    }

    public static final List<String> getUserRolesFromToken(String token) {
        Claims claims;
        try {
            claims = Jwts.parser()
                    .setSigningKey(jwtProperties.getJwtSigningKey())
                    .parseClaimsJws(token)
                    .getBody();
            System.out.println(claims.get("roles"));
        } catch (Exception e) {
            throw new BizException(CommonEnum.REFRESH_TOKEN_EXPIRED);
        }
        return (List<String>) claims.get("roles");
    }

    public static final String getUserNameFromToken(String token) {
        Claims claims;
        try {
            if (jwtProperties.isSwagger2Use()) {
                return "swagger-user";
            }
            claims = Jwts.parser()
                    .setSigningKey(jwtProperties.getJwtSigningKey())
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            throw new BizException(CommonEnum.REFRESH_TOKEN_EXPIRED);
        }
        System.out.println(claims.get("username"));
        return (String) claims.get("username");
    }

    public static final String getUserNameFromReq(HttpServletRequest request) {
        if (jwtProperties.isSwagger2Use()) {
            return "swagger-user";
        }
        return getUserNameFromToken(TokenUtils.getTokenFromRequest(request));
    }

    public static final String getRealNameFromToken(String token) {
        Claims claims;
        try {

            if (jwtProperties.isSwagger2Use()) {
                return "swagger-user";
            }
            claims = Jwts.parser()
                    .setSigningKey(jwtProperties.getJwtSigningKey())
                    .parseClaimsJws(token)
                    .getBody();
            System.out.println(claims.get("realName"));
        } catch (Exception e) {
            throw new BizException(CommonEnum.REFRESH_TOKEN_EXPIRED);
        }
        return (String) claims.get("realName");
    }

    public static final String getRealNameFromReq(HttpServletRequest request) {
        if (jwtProperties.isSwagger2Use()) {
            return "swagger-user";
        }
        return getRealNameFromToken(TokenUtils.getTokenFromRequest(request));
    }

    public static final Long getUserIdFromToken(String token) {
        Claims claims;
        try {
            claims = Jwts.parser()
                    .setSigningKey(jwtProperties.getJwtSigningKey())
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            throw new BizException(CommonEnum.REFRESH_TOKEN_EXPIRED);
        }
        return NumberUtils.toLong(claims.get("userId").toString());
    }

    public static boolean validate(String jwtToken) {
        Claims claims;
        try {
            claims = Jwts.parser()
                    .setSigningKey(jwtProperties.getJwtSigningKey())
                    .parseClaimsJws(jwtToken)
                    .getBody();
        } catch (Exception e) {
            log.error("【jwt 过期解析Exception e : {}】", e.getMessage());
            return false;
        }
        return claims.getExpiration().after(new Date());
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        jwtProperties = applicationContext.getBean(JwtProperties.class);
    }
}